﻿#region Using Statements
using System;
using System.Collections.Generic;
using DirectZZT.Shared.Core;
using DirectZZT.Shared.Input;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
#endregion

namespace DirectZZT.Input
{
    /// <summary>
    /// Provides an input manager for the keyboard (just like ol' ZZT) ;)
    /// </summary>
    [Export("Keyboard", Type = typeof(IInputManager))]
    public class KeyboardInputManager : IInputManager
    {
        #region Fields

        private KeyboardState _kbPrevious;
        private KeyboardState _kbCurrent;
        private MouseState _msPrevious;
        private MouseState _msCurrent;

        private Dictionary<string, InputCommand> _commands;
        private Dictionary<string, Keys> _inputBindings;
        #endregion

        #region Properties

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the KeyboardInputManager class.
        /// </summary>
        public KeyboardInputManager()
        {
            _inputBindings = new Dictionary<string, Keys>();
            _commands = new Dictionary<string, InputCommand>();

            _kbPrevious = Keyboard.GetState();
            _kbCurrent = _kbPrevious;
            _msPrevious = Mouse.GetState();
            _msCurrent = _msPrevious;
        }

        #endregion

        #region Methods

        #endregion

        #region IInputManager Members

        InputManagerDevices IInputManager.HandledDevices
        {
            get { return InputManagerDevices.Keyboard | InputManagerDevices.Mouse; }
        }

        /// <summary>
        /// Gets/sets the cursor position.
        /// </summary>
        public Vector2 CursorPosition
        {
            get { return new Vector2(_msCurrent.X, _msCurrent.Y); }
            set { Mouse.SetPosition((int)value.X, (int)value.Y); }
        }

        IEnumerable<InputBinding> IInputManager.GetBindings()
        {
            foreach (var item in _inputBindings)
            {
                yield return new InputBinding() { Action = item.Key, Code = (int)item.Value };
            }
        }

        void IInputManager.Bind(string action, int code)
        {
            // TODO: silly. doesn't allow for multiple bindings to the same action. prio 3
            _inputBindings[action] = (Keys)code;
        }

        void IInputManager.UnBind(string action)
        {
            _inputBindings.Remove(action);
        }

        void IInputManager.RegisterCommand(string name, InputCommand command)
        {
            _commands[name] = command;
        }

        bool IInputManager.GetActionInvoked(string action)
        {
            if (!_inputBindings.ContainsKey(action))
            {
                return false;
            }

            Keys key = _inputBindings[action];

            return _kbCurrent.IsKeyDown(key);
        }

        bool IInputManager.GetActionInvokedToggle(string action)
        {
            if (!_inputBindings.ContainsKey(action))
            {
                return false;
            }

            Keys key = _inputBindings[action];

            return _kbCurrent.IsKeyDown(key) && _kbPrevious.IsKeyUp(key);
        }

        float IInputManager.GetActionValue(string action)
        {
            if (!_inputBindings.ContainsKey(action))
            {
                return 0.0f;
            }

            Keys key = _inputBindings[action];

            return _kbCurrent.IsKeyDown(key) ? 1.0f : 0.0f;
        }

        bool IInputManager.IsAnyKey()
        {
            // dunno if this is required anymore
            return _kbCurrent.GetPressedKeys().Length > 0;
        }

        void IInputManager.Update()
        {
            _kbPrevious = _kbCurrent;
            _kbCurrent = Keyboard.GetState();
            _msPrevious = _msCurrent;
            _msCurrent = Mouse.GetState();
        }

        #endregion

        #region IDisposable Members

        void IDisposable.Dispose()
        {

        }

        #endregion
    }
}
